PostgreSQL 安全管理 scram-sha-256
1 背景知识
PostgreSQL的很多设计非常的工业化,比如开放了许多扩展接口(类型、操作符、索引、扫描、采样、数据库编程语言等)。这些接口能够提供给模块化开发程序,降低整体系统复杂度。 根据这一思想,所以认证也是模块化的,比如你不喜欢md5的认证方法,可以换认证模块,提高数据库安全性。 目前Postgersql 的认证方式有以下几种:
20.3.1. Trust Authentication
20.3.2. Password Authentication
20.3.3. GSSAPI Authentication
20.3.4. SSPI Authentication
20.3.5. Ident Authentication
20.3.6. Peer Authentication
20.3.7. LDAP Authentication
20.3.8. RADIUS Authentication
20.3.9. Certificate Authentication
20.3.10. PAM Authentication
20.3.11. BSD Authentication
从PostgreSQL 10.0开始,通过扩展认证协议,引入了一个全新的通用SASL认证方法。叫做SCRAM-SHA-256。SCRAM-SHA-256是基于SASL算法。
接下来就带领大家看看postgresql 10.0新增的SCRAM-SHA-256 BASE ON SASL认证吧。
2 MD5 认证机制
md5
认证机制的算法较为简单。客户端可以填写MD5 加密后的秘钥,就可以直接登录数据库。具体流程如下:
- 客户端:递交
md5
秘钥(服务端存储的秘钥+SALT)。 - 服务端:比较
md5
秘钥(md5(password)+salt)。 - 如果
md5
秘钥一致,将会认证通过。
从上述认证机制得出:为了安全起见,不要泄露使用MD5存储的秘钥。
对于更详细的MD5 秘钥认证方式,请见 [[#10 scram 和MD5 的兼容性实验]]
3 SCRAM认证机制
scram
机制认证能够避免 MD5
认证的问题,能保证客户端不被伪装,也能保证服务端不被伪装。提高安全性。
3.1 PostgreSQL 引入scram机制
PostgreSQL SCRAM
机制是由 RFC文档 5802 7677 补丁引入。和PG原有的GSS
和SSP
I认证相同,这种验证方式是由数据库端告诉客户端使用哪个SASL
认证机制,然后在认证过程中SASL消息通过 AuthenticationSASLcontinue
、PasswordMessage
两个过程进行信息交换。虽然Postgresql 目前只支持SCRAM-SHA-256
算法。但是基于SASL
认证方法,未来可以支持更多的算法。
3.2 SCRAM认证:客户端交互流程
- 客户端要将用户名发给服务端。
- 服务端收到客户端用户名后,从存储的密文中提取一些认证过程需要的
salt
,StoredKey
,ServerKey
, 以及循环次数
发送给客户端。
循环次数可能所有用户一致。
- 客户端接收到返回的信息之后,使用客户端掌握的用户密码对信息加工。
- 具体步骤如下:
1. SaltedPassword := Hi(Normalize(password), salt, i)
2. ClientKey := HMAC(SaltedPassword, "Client Key")
3. StoredKey := H(ClientKey)
4. AuthMessage := client-first-message-bare + "," +
server-first-message + "," +
client-final-message-without-proof
ClientSignature := HMAC(StoredKey, AuthMessage)
ClientProof := ClientKey XOR ClientSignature
ServerKey := HMAC(SaltedPassword, "Server Key")
ServerSignature := HMAC(ServerKey, AuthMessage)
6、服务端与客户端的交互过程会用到以上信息。
3.3 SCRAM认证:客户服务端交互流程
-
首先使用
ClientSignature
与ClientProof
进行异或
,得到ClientKey
。 -
服务端需要使用
哈希函数
处理ClientKey
,得到的结果与服务端存储的StoredKey
进行比较。如果ClientKey
正确,说明客户端认证通过。
客户端如果要防止服务端被伪装,也可以使用类似方法,客户端需要计算出ServerSignature,同时与服务端认证过程中返回的服务端根据存储的信息+客户端交换过程中提交的信息计算的(ServerSignature)进行比较,如果匹配则服务端没有被伪装。
安全在哪里?
服务端存储了多次加密后的秘钥,加密方法不可逆转。仅仅泄露这个多次加密后的秘钥,无法攻破数据库。
基于SASL认证方法,可以提高服务端与客户端防伪装的能力。
更多的scram机制请参考
RFC 5802 - Salted Challenge Response Authentication Mechanism (SCRAM) SASL and GSS-API Mechanisms
3.4 查看scram 秘钥视图
请参考pg的官方文档:pg_authid
字段名称 | 字段说明 |
---|---|
oid oid 行标识 |
|
rolname name |
角色名 |
rolsuper bool |
用户是否有超级用户权限 |
rolinherit bool |
角色是否有继承权限。 |
rolcreaterole bool |
角色是否能够创建更多用户。 |
rolcreatedb bool |
角色是否能够创建数据库。 |
rolcanlogin bool |
角色是否能够登录。 |
rolreplication bool |
是否有复制权限,可以启动复制连接,创建和删除复制槽。 |
rolbypassrls bool |
角色是否能够绕过行级安全策略。 |
rolconnlimit int4 |
角色最大连接数。 |
rolpassword text |
加密后的密码;如果未设置密码,则为空。 |
rolvaliduntil timestamptz |
密码的到期时间,如果没有过期则为 none 。 |
3.5 scram秘钥的结构解释
**scram的内容分为5段,具体解释如下 **
1、第一个结构:统一使用 scram-sha-256
字符串,表明要使用 scram-sha-256
方式验证密码。
2、第二个结构:是个 salt
,是使用 base64
编码的。
3、第三个结构:密码的加密次数,加密次数越多,安全性越好。
4、第四结构:以hexadecimal 格式存储的服务器秘钥和存储密码,respectively
秘钥。
The first field is the constant scram-sha-256, to identify the password as a SCRAM-SHA-256 verifier.
The second field is a salt, Base64-encoded,
and the third field is the number of iterations used to generate the password.
The fourth field and fifth field are the stored key and server key, respectively, in hexadecimal format.
3.6 PostgreSQL scram实现的代码
请参考 auth-scram.c 源码。
3.7 PostgreSQL SCRAM 认证的消息格式
https://www.postgresql.org/docs/devel/static/protocol-flow.html
AuthenticationSASL
The frontend must now initiate a SASL negotiation, using the SASL mechanism specified in the message.
The frontend will send a PasswordMessage with the first part of the SASL data stream in response to this.
If further messages are needed, the server will respond with AuthenticationSASLContinue.
AuthenticationSASLContinue
This message contains the response data from the previous step of SASL negotiation
(AuthenticationSASL, or a previous AuthenticationSASLContinue).
If the SASL data in this message indicates more data is needed to complete the authentication, the frontend must send that data as another PasswordMessage.
If SASL authentication is completed by this message, the server will next send AuthenticationOk to indicate successful authentication or ErrorResponse to indicate failure.
报文如下
https://www.postgresql.org/docs/devel/static/protocol-message-formats.html
AuthenticationSASL (B)
Byte1('R')
Identifies the message as an authentication request.
Int32
Length of message contents in bytes, including self.
Int32(10)
Specifies that SASL authentication is started.
String
Name of a SASL authentication mechanism.
AuthenticationSASLContinue (B)
Byte1('R')
Identifies the message as an authentication request.
Int32
Length of message contents in bytes, including self.
Int32(11)
Specifies that this message contains SASL-mechanism specific data.
Byten
SASL data, specific to the SASL mechanism being used.
4 scram 和MD5 的兼容性实验
数据库的安装过程请参考 PostgreSQL15。
4.1 修改pg_hba.conf 认证方式为scram
vi pg_hba.conf
host all all 127.0.0.1/32 scram-sha-256
4.2 创建md5秘钥存储用户
psql -h $PGDATA -p 5432 -U postgres postgres
SET password_encryption='md5';
CREATE USER user01 encrypted PASSWORD 'postgres';
//屏幕输出:
CREATE ROLE
4.3 创建scram秘钥存储用户
SET password_encryption='scram-sha-256';
CREATE USER user02 encrypted PASSWORD 'postgres';
//屏幕输出:
CREATE ROLE
4.4 查看md5和scram存储的区别
SELECT rolname,rolpassword FROM pg_authid;
//屏幕输出:
rolname | rolpassword
-------------------+-------------------
user01 | md53c4f4ac64686411b89a7711b9569cc4c
user02 | SCRAM-SHA-256$4096:oPqRPHaPYMtKicxRlP3rzQ==$GekA8kyoEADTMrfkamfd4FTAZD4NVbVwOf0Hj66rD10=:oPZiI82R3F2Qm8HVS3gZME9fDIISkQJUzYK
/TPmbhY0=
4.5 scram认证测试
1、user01 用户登录失败。
psql -h 127.0.0.1 -p 5432 -U user01 testdb
//屏幕输出:
Password for user user01:
psql: error received from server in SASL exchange: invalid-proof
2、user02 用户登录成功。
psql -h 127.0.0.1 -p 5432 -U user02 testdb
Password for user user02:
psql (10devel)
Type "help" for help.
postgres=>
4.6 设置为md5认证
vi pg_hba.conf
host all all 127.0.0.1/32 md5
4.7 重载数据库
pg_ctl reload
1、user01 登录成功。
psql -h 127.0.0.1 -p 5432 -U user01 postgres
Password for user user01:
psql (12.9)
Type "help" for help.
postgres=> \q
2、user02 登录成功。
psql -h 127.0.0.1 -p 5432 -U user02 postgres
//屏幕输出:
Password for user user02:
psql (12.9)
Type "help" for help
为了简化从md5方法到新的SCRAM方法的转换,如果在pg_hba.conf中将md5 指定为方法,但服务器上用户的密码是SCRAM加密的,那么自动选择基于SCRAM的认证。
PostgreSQL社区的作风非常严谨,一个patch
可能在邮件组中讨论几个月甚至几年,根据大家的意见反复的修正,patch
合并到master
已经非常成熟,所以PostgreSQL的稳定性也是远近闻名的。
5 小结
1、 [PostgreSQL]模块化的认证方法,给PostgreSQL的安全加固提供了很好的便利。
2、 SCRAM相比MD5,可以避免因为数据库存储的加密秘钥都是,客户端可以篡改认证协议连接数据库的危险。
3、 scram认证方法和md5认证方法是不兼容的,二者选一,旧的客户端不支持scram认证。
4、 PostgreSQL 10.0 通过扩展认证协议,引入了一个全新的通用SASL认证方法,目前基于SASL,已加入SCRAM-SHA-256算法的支持,未来可以支持更多的算法。